package com.shigi.sat;

import com.shigi.sat.structure.SatInstance;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by Miroslav Šiagi on 27/01/15.
 */
public class SatLoader {

    private List<SatInstance> instances;
    private SatInstance processingInstance;
    private int[] allWeights;
    private int clauseCounter = 0;

    public List<SatInstance> loadInstances() {
        this.instances = new ArrayList<>();
        File folder = new File(Configuration.INST_FOLDER_PATH);
        if(!folder.exists()) {
            folder.mkdirs();
        }

        for (File fileEntry : folder.listFiles()) {
            if (fileEntry.isFile()) {
                System.out.println("Reading file: " + fileEntry.getName() + " and creating SatInstance.");
                loadInputsFromFile(fileEntry);
            }
        }

        return this.instances;
    }

    private void loadInputsFromFile(File fileEntry) {
        String fileName = fileEntry.getName();
        try(BufferedReader br = new BufferedReader(new FileReader(fileEntry.getAbsolutePath()))) {
            String line = br.readLine();

            this.clauseCounter = 0;
            while (line != null) {
                processLine(line, fileName);
                line = br.readLine();
            }

        } catch(Exception ex) {
            System.out.println(ex.getMessage());
        }

        this.instances.add(this.processingInstance);
    }

    private void processLine(String line, String fileName) {
        String[] lineParts = line.split(" ");
        if(line.charAt(Configuration.MAIN_CHAR_POSITION) == Configuration.LINE_CONFIGURATION_CHAR) {
            this.processingInstance = new SatInstance(fileName,
                    Configuration.NUM_OF_LITERALS,
                    Integer.parseInt(lineParts[Configuration.NUM_OF_CLAUSES_POSITION]),
                    Integer.parseInt(lineParts[Configuration.NUM_OF_VARIABLES_POSITION]));

        } else if(line.charAt(Configuration.MAIN_CHAR_POSITION) == Configuration.LINE_WEIGHTS_CHAR) {
            initAllWeights(lineParts);
        } else if(clauseLine(line)) {
            setWeights(lineParts);
            this.clauseCounter++;
        }
    }

    private void initAllWeights(String[] lineParts) {
        this.allWeights = new int[lineParts.length - 1];

        for (int i = 1; i < lineParts.length; i++) {
            this.allWeights[i - 1] = Integer.parseInt(lineParts[i]);
            this.processingInstance.variablesWeights[i - 1] = Integer.parseInt(lineParts[i]);
        }
    }

    private boolean clauseLine(String line) {
        return  (line.charAt(Configuration.MAIN_CHAR_POSITION) != Configuration.LINE_WEIGHTS_CHAR
                &&
                line.charAt(Configuration.MAIN_CHAR_POSITION) != Configuration.LINE_COMMENT_CHAR);
    }

    private void setWeights(String[] lineParts) {
        int numOfLiterals = this.processingInstance.getNumOfLiterals();

        for (int j = 0; j < numOfLiterals; j++) {
            int literalIndex = Math.abs(Integer.parseInt(lineParts[j])) - 1;
            this.processingInstance.satClausules[clauseCounter].literals[j].index = literalIndex;
            this.processingInstance.satClausules[clauseCounter].literals[j].isPositive = (Integer.parseInt(lineParts[j]) >= 0);
            this.processingInstance.satClausules[clauseCounter].literals[j].weight = this.allWeights[literalIndex];
        }
    }
}
